<?php
/**
 * Copyright (c) [2019] [吴跃忠]
 * [selibra] is licensed under the Mulan PSL v1.
 * You can use this software according to the terms and conditions of the Mulan PSL v1.
 * You may obtain a copy of Mulan PSL v1 at:
 * http://license.coscl.org.cn/MulanPSL
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v1 for more details.
 */

namespace Selibra\Http\Lib;


use Selibra\Config\Config;
use Selibra\Http\Route\RouterConfig;
use Selibra\Tools\Console;
use Swoole\Http\Request as SwooleHttpRequest;
use Swoole\Http\Server;

class Request
{
    /**
     * @var SwooleHttpRequest
     */
    protected SwooleHttpRequest $swooleHttpRequest;

    /**
     * GET路由参数
     * @var array
     */
    protected array $routeParams = [];

    /**
     * @var Server
     */
    protected Server $httpServer;

    public function __construct(SwooleHttpRequest $request, Server $httpServer)
    {
        $this->swooleHttpRequest = $request;
        $this->httpServer = $httpServer;
    }


    /**
     * 设置路由参数
     * @param array $routeParams
     * @return $this
     */
    public function setRouteParams(array $routeParams): Request
    {
        $this->routeParams = $routeParams;
        return $this;
    }


    /**
     * @param $key
     * @return mixed
     */
    public function getPost($key = null)
    {
        if (is_null($key) || empty($this->swooleHttpRequest->post)) {
            return array_map(function ($item) {
                return self::paramFilter($item);
            }, $this->swooleHttpRequest->post ?: []);
        } elseif (!array_key_exists($key, $this->swooleHttpRequest->post)) {
            return null;
        }
        return self::paramFilter($this->swooleHttpRequest->post[$key]);
    }


    /**
     * @param $key
     * @return mixed
     */
    public function getGet($key = null)
    {
        $params = array_merge($this->swooleHttpRequest->get ?: [], $this->routeParams);
        if (is_null($key) || empty($this->swooleHttpRequest->get)) {
            return array_map(function ($item) {
                return self::paramFilter($item);
            }, $params ?: []);
        } elseif (!array_key_exists($key, $params)) {
            return null;
        }
        return self::paramFilter($params[$key]);
    }

    /**
     * @param $key
     * @return mixed
     */
    public function getDelete($key = null)
    {
        if (strtoupper($this->getMethod()) !== RouterConfig::REQUEST_DELETE) {
            return [];
        }
        $rawContent = $this->swooleHttpRequest->rawContent();
        parse_str($rawContent, $deleteData);
        if (is_null($key) || empty($deleteData)) {
            return array_merge($this->getPost() ?: [], $deleteData);
        } elseif (!array_key_exists($key, $deleteData)) {
            return $this->getPost($key);
        }
        return self::paramFilter($deleteData[$key]);
    }


    /**
     * @param $key
     * @return mixed
     */
    public function getPut($key = null)
    {
        if (strtoupper($this->getMethod()) !== RouterConfig::REQUEST_PUT) {
            return [];
        }
        $rawContent = $this->swooleHttpRequest->rawContent();
        parse_str($rawContent, $putData);
        if (is_null($key) || empty($putData)) {
            return array_merge($this->getPost() ?: [], $putData);;
        } elseif (!array_key_exists($key, $putData)) {
            return $this->getPost($key);
        }
        return array_merge($this->getPost() ?: [], self::paramFilter($putData[$key]));
    }


    /**
     * 获取上传的文件
     * @param null $key
     * @return mixed|null
     */
    public function getFile($key = null)
    {
        if (empty($key) || empty($this->swooleHttpRequest->files)) {
            return $this->swooleHttpRequest->files;
        } elseif (!array_key_exists($key, $this->swooleHttpRequest->files)) {
            return null;
        }
        return $this->swooleHttpRequest->files[$key];
    }


    /**
     * @return mixed
     */
    public function getMethod()
    {
        return $this->swooleHttpRequest->server['request_method'];
    }


    /**
     * @return mixed
     */
    public function getPathInfo()
    {
        return $this->swooleHttpRequest->server['path_info'];
    }


    /**
     * @param $key
     * @return mixed
     */
    public function getCookie($key)
    {
        if (empty($this->swooleHttpRequest->cookie)) {
            return null;
        }
        if (!array_key_exists($key, $this->swooleHttpRequest->cookie)) {
            return null;
        }
        return $this->swooleHttpRequest->cookie[$key];
    }


    /**
     * @param $key
     * @return mixed
     */
    public function getHeader($key)
    {
        if (!array_key_exists($key, $this->swooleHttpRequest->header)) {
            return null;
        }
        return $this->swooleHttpRequest->header[$key];
    }


    /**
     * @return SwooleHttpRequest
     */
    public function selectHeader()
    {
        return $this->swooleHttpRequest->header;
    }


    /**
     * @param null $key
     * @return array|mixed
     */
    public function server($key = null)
    {
        if (empty($key)) {
            return $this->swooleHttpRequest->server;
        } elseif (!array_key_exists($key, $this->swooleHttpRequest->server)) {
            return null;
        }
        return $this->swooleHttpRequest->server[$key];
    }


    /**
     * @return SwooleHttpRequest
     */
    public function getHttpRequest()
    {
        return $this->swooleHttpRequest;
    }


    public function getHost()
    {
        return $this->swooleHttpRequest->header['host'];
    }


    /**
     * 参数安全过滤
     * @param string|array $data
     */
    protected static function paramFilter(array|string $data)
    {
        $filterTypes = array_filter(explode(',', Config::get('application.http.param_filter')));
        if (!empty($filterTypes)) {
            if (is_array($data)) {
                foreach ($data as $key => $datum) {
                    foreach ($filterTypes as $filterType) {
                        if (is_array($datum)) {
                            $data[$key] = self::paramFilter($datum);
                        } else {
                            $data[$key] = $filterType($datum);
                        }
                    }
                }
            } else {
                foreach ($filterTypes as $filterType) {
                    $data = call_user_func_array($filterType, [$data]);
                }
            }
        }
        return $data;
    }


    /**
     * @return Server
     */
    public function getHttpServer()
    {
        return $this->httpServer;
    }
}
